//Copyright (C) 2011 Ron Coleman. Contact: ronncoleman@gmail.com
//
//This library is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 3 of the License, or (at your option) any later version.
//
//This library is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this library; if not, write to the Free Software
//Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
package bj.actor
import scala.actors.Actor
import bj.hkeeping.Ok
//import bj.actor.Player
import bj.table.Table
import scala.collection.mutable.HashMap
import bj.hkeeping.NotOk
import scala.actors.OutputChannel
import bj.util.Logs

case class Bet(player: Int, amt: Double)
case class GameStart(players: List[OutputChannel[Any]])
case class GameOver(payouts: HashMap[Int, Outcome], pid: Int)
case class Arrive(mailbox: OutputChannel[Any], player: Int, betAmt: Double)
case class Depart(mailbox: OutputChannel[Any], player: Int, betAmt: Double)
case class TableNumber(tid: Int)
case class TableNumberWithPrevBet(tid: Int, prevBet: Double)
case class Go

/** This object represents the house as a container of tables. */
object House extends Actor with Logs {
  var nextId = 0
  
/** Creates 3 Tables with minimum bets $5, $25, & $100 */
  var tables = List[Table](new Table(100, 1000), new Table(25, 99),  new Table(5, 24)) 
  var tableId = -1
  var betsHistory = HashMap[Int, TableNumberWithPrevBet]()

  override def toString = "house(" + nextId + ")"

  /** This method receives messages. */
  def act {  println("House started!")
    loop {
      react {
    
    /** Receives a bet from a player and matches it to a table */
        case Bet(pid: Int, bet: Double) =>
          debug("house: received bet amt = " + bet)

          tables.find(t => t.bets.size < Table.MAX_PLAYERS && t.minBet <= bet) match { //Find a Table that matches the bet
            case None =>
              sender ! NotOk  //Bet is < minBet

            case Some(table) =>
              debug("house: sending table id = " + table.tid + " sender = " + sender) 
              table ! Arrive(sender, pid, bet)  //Match found for bet >= minBet && bet <= maxBet; send player to table
              tableId=table.tid
              sender ! TableNumber(table.tid)  //send player table# generated
              
              for (x <- 1.to(betsHistory.size)) { debug("Bets History for: " + betsHistory.size + " tables = " + betsHistory) }
          }
          /**
           * Allows a player to move from table to table by
           * removing the player from the last table that s/he placed a bet at
           * if the current bet > the previous table's max bet
           */
          betsHistory.get(pid) match {
            case None => debug("Do Nothing for this player = " +  pid)
            case Some(lastBet) =>
              if (betsHistory.size > 1) {
                debug("bet=" + bet + ": lastBet.prevBet=" + lastBet.prevBet + ": tableBetMax" + tables(lastBet.tid).maxBet)
                if ((bet > lastBet.prevBet || bet < lastBet.prevBet) && (bet > tables(lastBet.tid).maxBet || bet < tables(lastBet.tid).minBet)) {
                  debug("Removing player = " + pid + " @ Table & Bet = " + lastBet)
                  tables(lastBet.tid).players.remove(pid)
                }
                  
                  
              }
          }
          
          /**
           * Store player's betting History = (PlayerId, TableId, Bet)
           */
          betsHistory += pid -> TableNumberWithPrevBet(tableId, bet)

        // Receives a message to tell the tables to go
        case Go =>
          debug("house: receive Go for " + tables.size + " tables")
          tables.foreach(t => t ! Go) //Maybe Go for 1 Table.tid

        // Receives something completely from left field
        case dontKnow =>
          // Got something we REALLY didn't expect
          debug(this + " got " + dontKnow)
      }
    }
  }
}